package todo.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class ServiceAspect {


    @Pointcut("execution(* Todo.service.*.*(..))")
    public void servicePointCut(){
    }


    final Map<String,Long> count= Collections.synchronizedMap(new HashMap<>());
    final Map<String,Long> totalTime= Collections.synchronizedMap(new HashMap<>());
    final Map<String,Long> maxTime= Collections.synchronizedMap(new HashMap<>());
    final Map<String,Long> minTime= Collections.synchronizedMap(new HashMap<>());
    final Map<String,Long> averageTime= Collections.synchronizedMap(new HashMap<>());
    final Map<String,Long> wrongCount= Collections.synchronizedMap(new HashMap<>());


    @Around("servicePointCut()")
    public void calculateTime(ProceedingJoinPoint joinPoint) throws Throwable {

        long t1= Calendar.getInstance().getTimeInMillis();
        joinPoint.proceed();
        long t2= Calendar.getInstance().getTimeInMillis();
        long spend=t2-t1;

        String APISig=joinPoint.getSignature().toString();

        if(count.containsKey(APISig)){
            count.replace(APISig,count.get(APISig)+1);
            totalTime.replace(APISig,totalTime.get(APISig)+spend);
            maxTime.replace(APISig,maxTime.get(APISig)>spend?maxTime.get(APISig):spend);
            minTime.replace(APISig,maxTime.get(APISig)<spend?maxTime.get(APISig):spend);
            averageTime.replace(APISig,totalTime.get(APISig)/count.get(APISig));
        }
        else {
            count.put(APISig, 1L);
            totalTime.put(APISig,spend);
            maxTime.put(APISig,spend);
            minTime.put(APISig,spend);
            averageTime.put(APISig,spend);
        }
    }


    @AfterThrowing("controllerPointCut()")
    public void doAfterThrowing(JoinPoint joinPoint) throws Throwable{
        String APISig=joinPoint.getSignature().toString();
        if(wrongCount.containsKey(APISig)){
            wrongCount.replace(APISig,wrongCount.get(APISig)+1);
        }
        else {
            wrongCount.put(APISig,1L);
        }

    }


    public Map<String, Long> getCount() {
        return count;
    }

    public Map<String, Long> getTotalTime() {
        return totalTime;
    }
    public Map<String, Long> getMaxTime() {
        return maxTime;
    }
    public Map<String, Long> getMinTime() {
        return minTime;
    }
    public Map<String, Long> getAverageTime() {
        return averageTime;
    }
    public Map<String, Long> getWrongCount() {
        return wrongCount;
    }
}
